home *** CD-ROM | disk | FTP | other *** search
/ PC/CD Gamer UK 120 / CD Gamer Issue 120 (March 2003) (Disc 2).ISO / mods / Q2_Codered / codeRED1_0.exe / Data1.cab / g_save.c1 < prev    next >
Encoding:
Text File  |  2002-08-13  |  18.7 KB  |  771 lines

  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20.  
  21. #include "g_local.h"
  22.  
  23. #define Function(f) {#f, f}
  24.  
  25. mmove_t mmove_reloc;
  26.  
  27. field_t fields[] = {
  28.     {"classname", FOFS(classname), F_LSTRING},
  29.     {"model", FOFS(model), F_LSTRING},
  30.     {"spawnflags", FOFS(spawnflags), F_INT},
  31.     {"speed", FOFS(speed), F_FLOAT},
  32.     {"accel", FOFS(accel), F_FLOAT},
  33.     {"decel", FOFS(decel), F_FLOAT},
  34.     {"target", FOFS(target), F_LSTRING},
  35.     {"targetname", FOFS(targetname), F_LSTRING},
  36.     {"pathtarget", FOFS(pathtarget), F_LSTRING},
  37.     {"deathtarget", FOFS(deathtarget), F_LSTRING},
  38.     {"killtarget", FOFS(killtarget), F_LSTRING},
  39.     {"combattarget", FOFS(combattarget), F_LSTRING},
  40.     {"message", FOFS(message), F_LSTRING},
  41.     {"team", FOFS(team), F_LSTRING},
  42.     {"wait", FOFS(wait), F_FLOAT},
  43.     {"delay", FOFS(delay), F_FLOAT},
  44.     {"random", FOFS(random), F_FLOAT},
  45.     {"move_origin", FOFS(move_origin), F_VECTOR},
  46.     {"move_angles", FOFS(move_angles), F_VECTOR},
  47.     {"style", FOFS(style), F_INT},
  48.     {"count", FOFS(count), F_INT},
  49.     {"health", FOFS(health), F_INT},
  50.     {"sounds", FOFS(sounds), F_INT},
  51.     {"light", 0, F_IGNORE},
  52.     {"dmg", FOFS(dmg), F_INT},
  53.     {"mass", FOFS(mass), F_INT},
  54.     {"volume", FOFS(volume), F_FLOAT},
  55.     {"attenuation", FOFS(attenuation), F_FLOAT},
  56.     {"map", FOFS(map), F_LSTRING},
  57.     {"origin", FOFS(s.origin), F_VECTOR},
  58.     {"angles", FOFS(s.angles), F_VECTOR},
  59.     {"angle", FOFS(s.angles), F_ANGLEHACK},
  60.  
  61.     {"goalentity", FOFS(goalentity), F_EDICT, FFL_NOSPAWN},
  62.     {"movetarget", FOFS(movetarget), F_EDICT, FFL_NOSPAWN},
  63.     {"enemy", FOFS(enemy), F_EDICT, FFL_NOSPAWN},
  64.     {"oldenemy", FOFS(oldenemy), F_EDICT, FFL_NOSPAWN},
  65.     {"activator", FOFS(activator), F_EDICT, FFL_NOSPAWN},
  66.     {"groundentity", FOFS(groundentity), F_EDICT, FFL_NOSPAWN},
  67.     {"teamchain", FOFS(teamchain), F_EDICT, FFL_NOSPAWN},
  68.     {"teammaster", FOFS(teammaster), F_EDICT, FFL_NOSPAWN},
  69.     {"owner", FOFS(owner), F_EDICT, FFL_NOSPAWN},
  70.     {"mynoise", FOFS(mynoise), F_EDICT, FFL_NOSPAWN},
  71.     {"mynoise2", FOFS(mynoise2), F_EDICT, FFL_NOSPAWN},
  72.     {"target_ent", FOFS(target_ent), F_EDICT, FFL_NOSPAWN},
  73.     {"chain", FOFS(chain), F_EDICT, FFL_NOSPAWN},
  74.  
  75.     {"prethink", FOFS(prethink), F_FUNCTION, FFL_NOSPAWN},
  76.     {"think", FOFS(think), F_FUNCTION, FFL_NOSPAWN},
  77.     {"blocked", FOFS(blocked), F_FUNCTION, FFL_NOSPAWN},
  78.     {"touch", FOFS(touch), F_FUNCTION, FFL_NOSPAWN},
  79.     {"use", FOFS(use), F_FUNCTION, FFL_NOSPAWN},
  80.     {"pain", FOFS(pain), F_FUNCTION, FFL_NOSPAWN},
  81.     {"die", FOFS(die), F_FUNCTION, FFL_NOSPAWN},
  82.  
  83.     {"stand", FOFS(monsterinfo.stand), F_FUNCTION, FFL_NOSPAWN},
  84.     {"idle", FOFS(monsterinfo.idle), F_FUNCTION, FFL_NOSPAWN},
  85.     {"search", FOFS(monsterinfo.search), F_FUNCTION, FFL_NOSPAWN},
  86.     {"walk", FOFS(monsterinfo.walk), F_FUNCTION, FFL_NOSPAWN},
  87.     {"run", FOFS(monsterinfo.run), F_FUNCTION, FFL_NOSPAWN},
  88.     {"dodge", FOFS(monsterinfo.dodge), F_FUNCTION, FFL_NOSPAWN},
  89.     {"attack", FOFS(monsterinfo.attack), F_FUNCTION, FFL_NOSPAWN},
  90.     {"melee", FOFS(monsterinfo.melee), F_FUNCTION, FFL_NOSPAWN},
  91.     {"sight", FOFS(monsterinfo.sight), F_FUNCTION, FFL_NOSPAWN},
  92.     {"checkattack", FOFS(monsterinfo.checkattack), F_FUNCTION, FFL_NOSPAWN},
  93.     {"currentmove", FOFS(monsterinfo.currentmove), F_MMOVE, FFL_NOSPAWN},
  94.  
  95.     {"endfunc", FOFS(moveinfo.endfunc), F_FUNCTION, FFL_NOSPAWN},
  96.  
  97.     // temp spawn vars -- only valid when the spawn function is called
  98.     {"lip", STOFS(lip), F_INT, FFL_SPAWNTEMP},
  99.     {"distance", STOFS(distance), F_INT, FFL_SPAWNTEMP},
  100.     {"height", STOFS(height), F_INT, FFL_SPAWNTEMP},
  101.     {"noise", STOFS(noise), F_LSTRING, FFL_SPAWNTEMP},
  102.     {"pausetime", STOFS(pausetime), F_FLOAT, FFL_SPAWNTEMP},
  103.     {"item", STOFS(item), F_LSTRING, FFL_SPAWNTEMP},
  104.  
  105. //need for item field in edict struct, FFL_SPAWNTEMP item will be skipped on saves
  106.     {"item", FOFS(item), F_ITEM},
  107.  
  108.     {"gravity", STOFS(gravity), F_LSTRING, FFL_SPAWNTEMP},
  109.     {"sky", STOFS(sky), F_LSTRING, FFL_SPAWNTEMP},
  110.     {"skyrotate", STOFS(skyrotate), F_FLOAT, FFL_SPAWNTEMP},
  111.     {"skyaxis", STOFS(skyaxis), F_VECTOR, FFL_SPAWNTEMP},
  112.     {"minyaw", STOFS(minyaw), F_FLOAT, FFL_SPAWNTEMP},
  113.     {"maxyaw", STOFS(maxyaw), F_FLOAT, FFL_SPAWNTEMP},
  114.     {"minpitch", STOFS(minpitch), F_FLOAT, FFL_SPAWNTEMP},
  115.     {"maxpitch", STOFS(maxpitch), F_FLOAT, FFL_SPAWNTEMP},
  116.     {"nextmap", STOFS(nextmap), F_LSTRING, FFL_SPAWNTEMP},
  117.  
  118.     {0, 0, 0, 0}
  119.  
  120. };
  121.  
  122. field_t        levelfields[] =
  123. {
  124.     {"changemap", LLOFS(changemap), F_LSTRING},
  125.                    
  126.     {"sight_client", LLOFS(sight_client), F_EDICT},
  127.     {"sight_entity", LLOFS(sight_entity), F_EDICT},
  128.     {"sound_entity", LLOFS(sound_entity), F_EDICT},
  129.     {"sound2_entity", LLOFS(sound2_entity), F_EDICT},
  130.  
  131.     {NULL, 0, F_INT}
  132. };
  133.  
  134. field_t        clientfields[] =
  135. {
  136.     {"pers.weapon", CLOFS(pers.weapon), F_ITEM},
  137.     {"pers.lastweapon", CLOFS(pers.lastweapon), F_ITEM},
  138.     {"newweapon", CLOFS(newweapon), F_ITEM},
  139.  
  140.     {NULL, 0, F_INT}
  141. };
  142.  
  143. /*
  144. ============
  145. InitGame
  146.  
  147. This will be called when the dll is first loaded, which
  148. only happens when a new game is started or a save game
  149. is loaded.
  150. ============
  151. */
  152. void InitGame (void)
  153. {
  154.     gi.dprintf ("==== InitGame ====\n");
  155.  
  156.     gun_x = gi.cvar ("gun_x", "0", 0);
  157.     gun_y = gi.cvar ("gun_y", "0", 0);
  158.     gun_z = gi.cvar ("gun_z", "0", 0);
  159.  
  160.     //FIXME: sv_ prefix is wrong for these
  161.     sv_rollspeed = gi.cvar ("sv_rollspeed", "200", 0);
  162.     sv_rollangle = gi.cvar ("sv_rollangle", "2", 0);
  163.     sv_maxvelocity = gi.cvar ("sv_maxvelocity", "2000", 0);
  164.     sv_gravity = gi.cvar ("sv_gravity", "800", 0);
  165.  
  166.     // noset vars
  167.     dedicated = gi.cvar ("dedicated", "0", CVAR_NOSET);
  168.  
  169.     // latched vars
  170.     sv_cheats = gi.cvar ("cheats", "0", CVAR_SERVERINFO|CVAR_LATCH);
  171.     gi.cvar ("gamename", GAMEVERSION , CVAR_SERVERINFO | CVAR_LATCH);
  172.     gi.cvar ("gamedate", __DATE__ , CVAR_SERVERINFO | CVAR_LATCH);
  173.  
  174.     maxclients = gi.cvar ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH);
  175.     maxspectators = gi.cvar ("maxspectators", "4", CVAR_SERVERINFO);
  176.     deathmatch = gi.cvar ("deathmatch", "0", CVAR_LATCH);
  177.     coop = gi.cvar ("coop", "0", CVAR_LATCH);
  178.     skill = gi.cvar ("skill", "1", CVAR_LATCH);
  179.     maxentities = gi.cvar ("maxentities", "1024", CVAR_LATCH);
  180.  
  181.     // change anytime vars
  182.     dmflags = gi.cvar ("dmflags", "0", CVAR_SERVERINFO);
  183.     fraglimit = gi.cvar ("fraglimit", "0", CVAR_SERVERINFO);
  184.     timelimit = gi.cvar ("timelimit", "0", CVAR_SERVERINFO);
  185.     password = gi.cvar ("password", "", CVAR_USERINFO);
  186.     spectator_password = gi.cvar ("spectator_password", "", CVAR_USERINFO);
  187.     needpass = gi.cvar ("needpass", "0", CVAR_SERVERINFO);
  188.     filterban = gi.cvar ("filterban", "1", 0);
  189.  
  190.     g_select_empty = gi.cvar ("g_select_empty", "0", CVAR_ARCHIVE);
  191.  
  192.     run_pitch = gi.cvar ("run_pitch", "0.002", 0);
  193.     run_roll = gi.cvar ("run_roll", "0.005", 0);
  194.     bob_up  = gi.cvar ("bob_up", "0.005", 0);
  195.     bob_pitch = gi.cvar ("bob_pitch", "0.002", 0);
  196.     bob_roll = gi.cvar ("bob_roll", "0.002", 0);
  197.  
  198.     // flood control
  199.     flood_msgs = gi.cvar ("flood_msgs", "4", 0);
  200.     flood_persecond = gi.cvar ("flood_persecond", "4", 0);
  201.     flood_waitdelay = gi.cvar ("flood_waitdelay", "10", 0);
  202.  
  203.     // dm map list
  204.     sv_maplist = gi.cvar ("sv_maplist", "", 0);
  205.  
  206.     // items
  207.     InitItems ();
  208.  
  209.     Com_sprintf (game.helpmessage1, sizeof(game.helpmessage1), "");
  210.  
  211.     Com_sprintf (game.helpmessage2, sizeof(game.helpmessage2), "");
  212.  
  213.     // initialize all entities for this game
  214.     game.maxentities = maxentities->value;
  215.     g_edicts =  gi.TagMalloc (game.maxentities * sizeof(g_edicts[0]), TAG_GAME);
  216.     globals.edicts = g_edicts;
  217.     globals.max_edicts = game.maxentities;
  218.  
  219.     // initialize all clients for this game
  220.     game.maxclients = maxclients->value;
  221.     game.clients = gi.TagMalloc (game.maxclients * sizeof(game.clients[0]), TAG_GAME);
  222.     globals.num_edicts = game.maxclients+1;
  223. }
  224.  
  225. //=========================================================
  226.  
  227. void WriteField1 (FILE *f, field_t *field, byte *base)
  228. {
  229.     void        *p;
  230.     int            len;
  231.     int            index;
  232.  
  233.     if (field->flags & FFL_SPAWNTEMP)
  234.         return;
  235.  
  236.     p = (void *)(base + field->ofs);
  237.     switch (field->type)
  238.     {
  239.     case F_INT:
  240.     case F_FLOAT:
  241.     case F_ANGLEHACK:
  242.     case F_VECTOR:
  243.     case F_IGNORE:
  244.         break;
  245.  
  246.     case F_LSTRING:
  247.     case F_GSTRING:
  248.         if ( *(char **)p )
  249.             len = strlen(*(char **)p) + 1;
  250.         else
  251.             len = 0;
  252.         *(int *)p = len;
  253.         break;
  254.     case F_EDICT:
  255.         if ( *(edict_t **)p == NULL)
  256.             index = -1;
  257.         else
  258.             index = *(edict_t **)p - g_edicts;
  259.         *(int *)p = index;
  260.         break;
  261.     case F_CLIENT:
  262.         if ( *(gclient_t **)p == NULL)
  263.             index = -1;
  264.         else
  265.             index = *(gclient_t **)p - game.clients;
  266.         *(int *)p = index;
  267.         break;
  268.     case F_ITEM:
  269.         if ( *(edict_t **)p == NULL)
  270.             index = -1;
  271.         else
  272.             index = *(gitem_t **)p - itemlist;
  273.         *(int *)p = index;
  274.         break;
  275.  
  276.     //relative to code segment
  277.     case F_FUNCTION:
  278.         if (*(byte **)p == NULL)
  279.             index = 0;
  280.         else
  281.             index = *(byte **)p - ((byte *)InitGame);
  282.         *(int *)p = index;
  283.         break;
  284.  
  285.     //relative to data segment
  286.     case F_MMOVE:
  287.         if (*(byte **)p == NULL)
  288.             index = 0;
  289.         else
  290.             index = *(byte **)p - (byte *)&mmove_reloc;
  291.         *(int *)p = index;
  292.         break;
  293.  
  294.     default:
  295.         gi.error ("WriteEdict: unknown field type");
  296.     }
  297. }
  298.  
  299.  
  300. void WriteField2 (FILE *f, field_t *field, byte *base)
  301. {
  302.     int            len;
  303.     void        *p;
  304.  
  305.     if (field->flags & FFL_SPAWNTEMP)
  306.         return;
  307.  
  308.     p = (void *)(base + field->ofs);
  309.     switch (field->type)
  310.     {
  311.     case F_LSTRING:
  312.         if ( *(char **)p )
  313.         {
  314.             len = strlen(*(char **)p) + 1;
  315.             fwrite (*(char **)p, len, 1, f);
  316.         }
  317.         break;
  318.     }
  319. }
  320.  
  321. void ReadField (FILE *f, field_t *field, byte *base)
  322. {
  323.     void        *p;
  324.     int            len;
  325.     int            index;
  326.  
  327.     if (field->flags & FFL_SPAWNTEMP)
  328.         return;
  329.  
  330.     p = (void *)(base + field->ofs);
  331.     switch (field->type)
  332.     {
  333.     case F_INT:
  334.     case F_FLOAT:
  335.     case F_ANGLEHACK:
  336.     case F_VECTOR:
  337.     case F_IGNORE:
  338.         break;
  339.  
  340.     case F_LSTRING:
  341.         len = *(int *)p;
  342.         if (!len)
  343.             *(char **)p = NULL;
  344.         else
  345.         {
  346.             *(char **)p = gi.TagMalloc (len, TAG_LEVEL);
  347.             fread (*(char **)p, len, 1, f);
  348.         }
  349.         break;
  350.     case F_EDICT:
  351.         index = *(int *)p;
  352.         if ( index == -1 )
  353.             *(edict_t **)p = NULL;
  354.         else
  355.             *(edict_t **)p = &g_edicts[index];
  356.         break;
  357.     case F_CLIENT:
  358.         index = *(int *)p;
  359.         if ( index == -1 )
  360.             *(gclient_t **)p = NULL;
  361.         else
  362.             *(gclient_t **)p = &game.clients[index];
  363.         break;
  364.     case F_ITEM:
  365.         index = *(int *)p;
  366.         if ( index == -1 )
  367.             *(gitem_t **)p = NULL;
  368.         else
  369.             *(gitem_t **)p = &itemlist[index];
  370.         break;
  371.  
  372.     //relative to code segment
  373.     case F_FUNCTION:
  374.         index = *(int *)p;
  375.         if ( index == 0 )
  376.             *(byte **)p = NULL;
  377.         else
  378.             *(byte **)p = ((byte *)InitGame) + index;
  379.         break;
  380.  
  381.     //relative to data segment
  382.     case F_MMOVE:
  383.         index = *(int *)p;
  384.         if (index == 0)
  385.             *(byte **)p = NULL;
  386.         else
  387.             *(byte **)p = (byte *)&mmove_reloc + index;
  388.         break;
  389.  
  390.     default:
  391.         gi.error ("ReadEdict: unknown field type");
  392.     }
  393. }
  394.  
  395. //=========================================================
  396.  
  397. /*
  398. ==============
  399. WriteClient
  400.  
  401. All pointer variables (except function pointers) must be handled specially.
  402. ==============
  403. */
  404. void WriteClient (FILE *f, gclient_t *client)
  405. {
  406.     field_t        *field;
  407.     gclient_t    temp;
  408.     
  409.     // all of the ints, floats, and vectors stay as they are
  410.     temp = *client;
  411.  
  412.     // change the pointers to lengths or indexes
  413.     for (field=clientfields ; field->name ; field++)
  414.     {
  415.         WriteField1 (f, field, (byte *)&temp);
  416.     }
  417.  
  418.     // write the block
  419.     fwrite (&temp, sizeof(temp), 1, f);
  420.  
  421.     // now write any allocated data following the edict
  422.     for (field=clientfields ; field->name ; field++)
  423.     {
  424.         WriteField2 (f, field, (byte *)client);
  425.     }
  426. }
  427.  
  428. /*
  429. ==============
  430. ReadClient
  431.  
  432. All pointer variables (except function pointers) must be handled specially.
  433. ==============
  434. */
  435. void ReadClient (FILE *f, gclient_t *client)
  436. {
  437.     field_t        *field;
  438.  
  439.     fread (client, sizeof(*client), 1, f);
  440.  
  441.     for (field=clientfields ; field->name ; field++)
  442.     {
  443.         ReadField (f, field, (byte *)client);
  444.     }
  445. }
  446.  
  447. /*
  448. ============
  449. WriteGame
  450.  
  451. This will be called whenever the game goes to a new level,
  452. and when the user explicitly saves the game.
  453.  
  454. Game information include cross level data, like multi level
  455. triggers, help computer info, and all client states.
  456.  
  457. A single player death will automatically restore from the
  458. last save position.
  459. ============
  460. */
  461. void WriteGame (char *filename, qboolean autosave)
  462. {
  463.     FILE    *f;
  464.     int        i;
  465.     char    str[16];
  466.  
  467.     if (!autosave)
  468.         SaveClientData ();
  469.  
  470.     f = fopen (filename, "wb");
  471.     if (!f)
  472.         gi.error ("Couldn't open %s", filename);
  473.  
  474.     memset (str, 0, sizeof(str));
  475.     strcpy (str, __DATE__);
  476.     fwrite (str, sizeof(str), 1, f);
  477.  
  478.     game.autosaved = autosave;
  479.     fwrite (&game, sizeof(game), 1, f);
  480.     game.autosaved = false;
  481.  
  482.     for (i=0 ; i<game.maxclients ; i++)
  483.         WriteClient (f, &game.clients[i]);
  484.  
  485.     fclose (f);
  486. }
  487.  
  488. void ReadGame (char *filename)
  489. {
  490.     FILE    *f;
  491.     int        i;
  492.     char    str[16];
  493.  
  494.     gi.FreeTags (TAG_GAME);
  495.  
  496.     f = fopen (filename, "rb");
  497.     if (!f)
  498.         gi.error ("Couldn't open %s", filename);
  499.  
  500.     fread (str, sizeof(str), 1, f);
  501.     if (strcmp (str, __DATE__))
  502.     {
  503.         fclose (f);
  504.         gi.error ("Savegame from an older version.\n");
  505.     }
  506.  
  507.     g_edicts =  gi.TagMalloc (game.maxentities * sizeof(g_edicts[0]), TAG_GAME);
  508.     globals.edicts = g_edicts;
  509.  
  510.     fread (&game, sizeof(game), 1, f);
  511.     game.clients = gi.TagMalloc (game.maxclients * sizeof(game.clients[0]), TAG_GAME);
  512.     for (i=0 ; i<game.maxclients ; i++)
  513.         ReadClient (f, &game.clients[i]);
  514.  
  515.     fclose (f);
  516. }
  517.  
  518. //==========================================================
  519.  
  520.  
  521. /*
  522. ==============
  523. WriteEdict
  524.  
  525. All pointer variables (except function pointers) must be handled specially.
  526. ==============
  527. */
  528. void WriteEdict (FILE *f, edict_t *ent)
  529. {
  530.     field_t        *field;
  531.     edict_t        temp;
  532.  
  533.     // all of the ints, floats, and vectors stay as they are
  534.     temp = *ent;
  535.  
  536.     // change the pointers to lengths or indexes
  537.     for (field=fields ; field->name ; field++)
  538.     {
  539.         WriteField1 (f, field, (byte *)&temp);
  540.     }
  541.  
  542.     // write the block
  543.     fwrite (&temp, sizeof(temp), 1, f);
  544.  
  545.     // now write any allocated data following the edict
  546.     for (field=fields ; field->name ; field++)
  547.     {
  548.         WriteField2 (f, field, (byte *)ent);
  549.     }
  550.  
  551. }
  552.  
  553. /*
  554. ==============
  555. WriteLevelLocals
  556.  
  557. All pointer variables (except function pointers) must be handled specially.
  558. ==============
  559. */
  560. void WriteLevelLocals (FILE *f)
  561. {
  562.     field_t        *field;
  563.     level_locals_t        temp;
  564.  
  565.     // all of the ints, floats, and vectors stay as they are
  566.     temp = level;
  567.  
  568.     // change the pointers to lengths or indexes
  569.     for (field=levelfields ; field->name ; field++)
  570.     {
  571.         WriteField1 (f, field, (byte *)&temp);
  572.     }
  573.  
  574.     // write the block
  575.     fwrite (&temp, sizeof(temp), 1, f);
  576.  
  577.     // now write any allocated data following the edict
  578.     for (field=levelfields ; field->name ; field++)
  579.     {
  580.         WriteField2 (f, field, (byte *)&level);
  581.     }
  582. }
  583.  
  584.  
  585. /*
  586. ==============
  587. ReadEdict
  588.  
  589. All pointer variables (except function pointers) must be handled specially.
  590. ==============
  591. */
  592. void ReadEdict (FILE *f, edict_t *ent)
  593. {
  594.     field_t        *field;
  595.  
  596.     fread (ent, sizeof(*ent), 1, f);
  597.  
  598.     for (field=fields ; field->name ; field++)
  599.     {
  600.         ReadField (f, field, (byte *)ent);
  601.     }
  602. }
  603.  
  604. /*
  605. ==============
  606. ReadLevelLocals
  607.  
  608. All pointer variables (except function pointers) must be handled specially.
  609. ==============
  610. */
  611. void ReadLevelLocals (FILE *f)
  612. {
  613.     field_t        *field;
  614.  
  615.     fread (&level, sizeof(level), 1, f);
  616.  
  617.     for (field=levelfields ; field->name ; field++)
  618.     {
  619.         ReadField (f, field, (byte *)&level);
  620.     }
  621. }
  622.  
  623. /*
  624. =================
  625. WriteLevel
  626.  
  627. =================
  628. */
  629. void WriteLevel (char *filename)
  630. {
  631.     int        i;
  632.     edict_t    *ent;
  633.     FILE    *f;
  634.     void    *base;
  635.  
  636.     f = fopen (filename, "wb");
  637.     if (!f)
  638.         gi.error ("Couldn't open %s", filename);
  639.  
  640.     // write out edict size for checking
  641.     i = sizeof(edict_t);
  642.     fwrite (&i, sizeof(i), 1, f);
  643.  
  644.     // write out a function pointer for checking
  645.     base = (void *)InitGame;
  646.     fwrite (&base, sizeof(base), 1, f);
  647.  
  648.     // write out level_locals_t
  649.     WriteLevelLocals (f);
  650.  
  651.     // write out all the entities
  652.     for (i=0 ; i<globals.num_edicts ; i++)
  653.     {
  654.         ent = &g_edicts[i];
  655.         if (!ent->inuse)
  656.             continue;
  657.         fwrite (&i, sizeof(i), 1, f);
  658.         WriteEdict (f, ent);
  659.     }
  660.     i = -1;
  661.     fwrite (&i, sizeof(i), 1, f);
  662.  
  663.     fclose (f);
  664. }
  665.  
  666.  
  667. /*
  668. =================
  669. ReadLevel
  670.  
  671. SpawnEntities will allready have been called on the
  672. level the same way it was when the level was saved.
  673.  
  674. That is necessary to get the baselines
  675. set up identically.
  676.  
  677. The server will have cleared all of the world links before
  678. calling ReadLevel.
  679.  
  680. No clients are connected yet.
  681. =================
  682. */
  683. void ReadLevel (char *filename)
  684. {
  685.     int        entnum;
  686.     FILE    *f;
  687.     int        i;
  688.     void    *base;
  689.     edict_t    *ent;
  690.  
  691.     f = fopen (filename, "rb");
  692.     if (!f)
  693.         gi.error ("Couldn't open %s", filename);
  694.  
  695.     // free any dynamic memory allocated by loading the level
  696.     // base state
  697.     gi.FreeTags (TAG_LEVEL);
  698.  
  699.     // wipe all the entities
  700.     memset (g_edicts, 0, game.maxentities*sizeof(g_edicts[0]));
  701.     globals.num_edicts = maxclients->value+1;
  702.  
  703.     // check edict size
  704.     fread (&i, sizeof(i), 1, f);
  705.     if (i != sizeof(edict_t))
  706.     {
  707.         fclose (f);
  708.         gi.error ("ReadLevel: mismatched edict size");
  709.     }
  710.  
  711.     // check function pointer base address
  712.     fread (&base, sizeof(base), 1, f);
  713. #ifdef _WIN32
  714.     if (base != (void *)InitGame)
  715.     {
  716.         fclose (f);
  717.         gi.error ("ReadLevel: function pointers have moved");
  718.     }
  719. #else
  720.     gi.dprintf("Function offsets %d\n", ((byte *)base) - ((byte *)InitGame));
  721. #endif
  722.  
  723.     // load the level locals
  724.     ReadLevelLocals (f);
  725.  
  726.     // load all the entities
  727.     while (1)
  728.     {
  729.         if (fread (&entnum, sizeof(entnum), 1, f) != 1)
  730.         {
  731.             fclose (f);
  732.             gi.error ("ReadLevel: failed to read entnum");
  733.         }
  734.         if (entnum == -1)
  735.             break;
  736.         if (entnum >= globals.num_edicts)
  737.             globals.num_edicts = entnum+1;
  738.  
  739.         ent = &g_edicts[entnum];
  740.         ReadEdict (f, ent);
  741.  
  742.         // let the server rebuild world links for this ent
  743.         memset (&ent->area, 0, sizeof(ent->area));
  744.         gi.linkentity (ent);
  745.     }
  746.  
  747.     fclose (f);
  748.  
  749.     // mark all clients as unconnected
  750.     for (i=0 ; i<maxclients->value ; i++)
  751.     {
  752.         ent = &g_edicts[i+1];
  753.         ent->client = game.clients + i;
  754.         ent->client->pers.connected = false;
  755.     }
  756.  
  757.     // do any load time things at this point
  758.     for (i=0 ; i<globals.num_edicts ; i++)
  759.     {
  760.         ent = &g_edicts[i];
  761.  
  762.         if (!ent->inuse)
  763.             continue;
  764.  
  765.         // fire any cross-level triggers
  766.         if (ent->classname)
  767.             if (strcmp(ent->classname, "target_crosslevel_target") == 0)
  768.                 ent->nextthink = level.time + ent->delay;
  769.     }
  770. }
  771.